Taking Starquest to another level -
Adding levels is simply a matter of reusing the game processing, but adding an element of greater complexity or difficulty (or both) to each level. It also requires we track the level the user is currently on, and display information to the user. In the case of our game, the user passes from the current level into the next level when they pass through the stargate.
To add to the complexity, each time the user advances a level the star field is prepopulated with greater numbers of "k" mines. By the time the user reaches the 10th level more than a third of the starfield is seeded with these mines, making navigation treacherous, and increasing the probability the ship will be hit by a mine.
I have arbitrarily set the number of levels the user is required to complete to win at 10 - any more, and finishing would be impossible. Once the 10th level is completed the user is declared the winner. It is possible to let the user simply play and play trying to get the highest score before they run out of ships, but this was not my goal in game design. It might be yours.
To implement levels, requires that we track the current level we are on. At the beginning of the game you will of course be on level 1. We assign this to the variable "level" with the following code:
'Track the level level = 1
Also, we had been simply creating the starmap once at the beginning of the game play as we fell through the initialization code. Now it will be necessary to recreate the starmap with each new level when that level is begun. To do this I have encapsulated the starmap generation code into a simple subroutine. Here is that subroutine which appears much later in the code now:
[formStarmap] 'form the starmap for x = 1 to 8 : for y = 1 to 12 : starmap$(x,y) = "." : next y : next x starmap$(1,1) = "@" starmap$(7,11) = "*" starmap$(7,12) = "*" starmap$(8,11) = "*" starmap$(8,12) = "" 'depending on the level, populate the starmap with k mines for q = 1 to ((level-1)*3) gosub [laymine] next q return
Notice that I have added code to the routine that did not appear in the earlier inline code fragment. This is a simple loop that calls another subroutine to lay a mine at a random location. The called routine is another code fragment that has been moved to a dedicated subroutine. We will discuss it in a few moments. The number of mines to lay is dependant on the number of iterations the loop makes, which is defined by the following equation:
((level-1)*3)
which is the current level minus one and multiplied by three.
If the current level is one, then the equation will yield a zero. If the current level is two, then the equation will yield a three.
Note that this subroutine is called immediately after the level is set to 1 in the program initialization. Here is that code fragment:
'new new - starmap formed moved to subroutine 'build the starmap gosub [formStarmap]
Level does not really figure into game play again until the user passes through the stargate. Now we will do much the same sort of processing we did in the [winner] subroutine. We will determine the users score in preparation for letting the user know how well they are doing. We will also check to see if the user has just completed level 10 (the final level needed in order to win) - if so then we will call the [winner] subroutine to complete the game.
If the game was not over, we need to display the results to the user, then begin resetting the variables used to track the progress in the game, after which we can reset the map and start the next level. We have hashed over the mechanics of most of this in one form or another in this issue or the last, lets simply take a look at how it is done:
'If this is the stargate portal - you win.
if shipx = 8 and shipy = 12 then
'lets calculate the score
s = lives * 1000
t = (25 - move)*100
u = energy * 25
score = score + s + t + u
'now we go up a level (if level = 10 you win)
if level = 10 then [winner]
level = level + 1
'now we initialize the starmap again.
gosub [formStarmap]
'Tell the user what happened
cls
print
print "======================================================"
print "You have passed through the stargate..."
print
print " ...and emerged in another star system."
print "======================================================"
print
print "You scored ";s + t + u;" points completing level ";level-1
print " ships remaining (";lives;") = ";s;" points"
print " movement score (";move;" moves) = ";t;" points"
print " remaining energy bonus (";energy;"gj) = ";u;" points"
print
print " *** Current score for game = ";score;" ***"
print
print "======================================================="
print "You have advanced to level: ";level;", good luck!"
input "Press ENTER to continue...";a$
'reset the move counter back 1
move = 1
'you keep your energy - put ship back at 1,1
shipx = 1
shipy = 1
'go up to main loop and begin again...
goto [loop]
One thing that may not be immediately obvious is that I have reset the "move" variable to one. This would not have been necessary if the score mechanism did not depend on moves, but since you are scored on number of move more or less from 25, then we must restart a one each level. It might be nice to track total moves for the game, but I did not implement this.
Notice now that score is cumulative from level to level. Of course this is the way you want it. You don't want to have to give up your score each time you advance a level. This is done by adding the current levels score to the existing score in the following line:
score = score + s + t + u
Adding levels required a few other changes in some unusual places. One of these I eluded to earlier - the breaking out of the mine laying code from the [placemine] subroutine. This was necessary because of our need to randomly lay mines during setup (something the [placemine] subroutine did well) without the extra processing of determining whether the mine hit the ship, or reporting where the mine was placed. By breaking this bit of code out I was able to reuse the code unit for both needs, in the initialization of a starmap and in the placement of a mine during game play. This is the basics of another concept in programming called "Code Reuse". Here is the change to the [placemines] subroutine and the new [laymine] subroutine:
[placemine] 'now we place another of those pesky K mines 'x and y will equal location of mine on return from gosub... gosub [laymine] 'tell the user what happened print "A 'k' mine was placed at star position ";x;",";y 'see if the ship was there... if shipx = x and shipy = y then [hitmine] '-------------------------------------------------------------------------- 'this is new - moved it out of [placemine] [laymine] 'this routine actually lays the mine [relaymine] 'a flag to track successful placement of a mine (1 = no good, 0 = good) placement = 0 'select a random location... x = int(rnd(0)*8)+1 y = int(rnd(0)*12)+1 'make sure the mine is not placed in an invalid location if x = 8 and y = 12 then placement = 1 if x = 7 and y = 12 then placement = 1 if x = 7 and y = 11 then placement = 1 if x = 8 and y = 11 then placement = 1 if x = 1 and y = 1 then placement = 1 'if there is already a mine there then choose again if starmap$(x,y) = "k" then placement = 1 if placement = 1 then goto [relaymine] 'the placement failed - try again 'this location works - add the mine to the starmap starmap$(x,y) = "k" return
With a bit of examination of the code from our last series, you will see where the two parts were separated into distinct subroutines. I would have preferred write the [laymine] subroutine in an endless loop and exited the loop only when all a mine was successfully laid, but we have not covered these topics yet, so I stuck with what we know - the trusty goto in a conditional loop. The purpose of the conditional loop is to make sure that the mine is being laid in a valid location, a location not occupied by the stargate or another mine. If the location is not valid, we branch back up to the [relaymine] label and try it again.
Several other cosmetic changes were made to accommodate the new level orientation. I added the display of the current level to the [showmap] subroutine. I changed the instructions a little bit and above all - I added a little surprising display show to the end of the game. You will just have to play it and win to see it. Suffice to say it depends on the MainWin implementation of the LOCATE command (see installment 5 - Glossary).
I have jumped a round a lot demonstrating the changes and enhancements to make to further enhance the interest of the game. Many more enhancements remain. I fear that my code examples have been kind of chop and stick, and continuity has been lost. Please consult Appendix A for a full source code listing. Play and have fun.